using System;
using System.Collections;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
using System.Collections.Generic;

namespace Kym.Testing
{
    public static class SpecificationExtensions
    {
        public static void should_be_thrown_by(this Type exceptionType, Func<object> action)
        {
            try
            {
                action();
            }
            catch (Exception ex)
            {
                Assert.That(ex, Is.InstanceOfType(exceptionType));
                return;
            }

            throw new AssertionException(string.Format("Expected exception of type {0} but no exception was raised.",
                                                       exceptionType));
        }

        public static void should_be_false(this object value)
        {
            Assert.That(value, Is.False);
        }

        public static void should_be_true(this object value)
        {
            Assert.That(value, Is.True);
        }

        public static void should_be_equal_to<T>(this T value, T other)
        {
            Assert.That(value, Is.EqualTo(other));
        }

        public static T should_be_of_type<T>(this object value)
        {
            Assert.That(value, Is.TypeOf(typeof(T)));
            return (T)value;
        }

        public static void should_be_equivalent_to<T>(this IEnumerable<T> value, IEnumerable<T> other)
        {
            CollectionAssert.AreEquivalent(value, other);
        }

        public static void should_not_be_equal_to<T>(this T value, T other)
        {
            Assert.That(value, Is.Not.EqualTo(other));
        }

        public static void should_not_be_the_same_as<T>(this T value, T other)
        {
            Assert.That(value, Is.Not.SameAs(other));
        }

        public static void should_be_less_than<T>(this T value, T other) where T : IComparable
        {
            Assert.That(value, Is.LessThan(other));
        }

        public static IShouldBeInRange<T> should_differ_at_most_of<T, V>(this T value, V range) where T : IComparable
        {
            return new ShouldBeInRange<T, V>(value, range);
        }
    }
}